#include<WinSock2.h>
#include<string>
#include<iostream>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
#define MAX_CLIENT_NUM 64
#define MAX_BUFSIZE 1024
const int port = 8000;
int connectionNum = 0;
int sentNum = 0;
char recvBuf[MAX_BUFSIZE];

int id[100];
SOCKADDR_IN addrClients[100];
int availableId = 0;

int getid(SOCKADDR_IN addrClient) {
	for (int i = 0; i < availableId; i++) {
		if (id[i] != -1 && !strcmp(inet_ntoa(addrClient.sin_addr), inet_ntoa(addrClients[i].sin_addr)) && addrClient.sin_port == addrClients[i].sin_port) {
			return i;
		}
	}
	return -1;
}
string getname(int id) {
	string nameStr = to_string(id);
	if (id < 10) {
		nameStr = "0" + nameStr;
	}
	nameStr = "[" + nameStr + "]";
	return nameStr;
}
void addClient(SOCKADDR_IN addrClient) {
	SOCKADDR_IN addr(addrClient);
	id[availableId] = availableId;
	addrClients[availableId] = addr;
	availableId++;
}
void removeClient(SOCKADDR_IN addrClient) {
	for (int i = 0; i < availableId; i++) {
		if (id[i] != -1 && !strcmp(inet_ntoa(addrClient.sin_addr), inet_ntoa(addrClients[i].sin_addr)) && addrClient.sin_port == addrClients[i].sin_port) {
			id[i] = -1;
			break;
		}
	}
}

char* curTime() {
	time_t t = time(0);
	return ctime(&t);
}

//收消息
DWORD WINAPI receiver(LPVOID lpParameter) {
	SOCKET* clientSocket = (SOCKET*)(LPVOID)lpParameter;
	SOCKADDR_IN addrClient;
	int len = sizeof(addrClient);
	getpeername(*clientSocket, (struct sockaddr*)&addrClient, &len);
	//###收消息
	while (true) {
		if (recvBuf[0] != 0) {
			continue;
		}
		//正常收到消息
		if (recv(*clientSocket, recvBuf, sizeof(recvBuf), 0) > 0) {
			//收到/exit则断开连接
			string recvMsg = recvBuf;
			if (!strcmp(recvMsg.substr(14).c_str(), "/exit")) {
				cout << "[System] Client " << inet_ntoa(addrClient.sin_addr) << ": " << ntohs(addrClient.sin_port) << " exit\n";
				char exitMsg[] = "/exitok\n";
				if (send(*clientSocket, exitMsg, sizeof(exitMsg), 0) < 0) {
					cout << "Exit confirmation was not sent out.\n";
				}
				memset(recvBuf, 0, 1024);
				closesocket(*clientSocket);
				connectionNum--;
				removeClient(addrClient);
				return 0;
			}
			//正常聊天消息
			else {
				recvMsg = recvBuf;
				char serverTimeStr[11];
				strcpy(serverTimeStr, recvMsg.substr(4, 10).c_str());
				serverTimeStr[10] = 0;
				time_t serverTimeVal = atoi(serverTimeStr);
				char* sendTime = ctime(&serverTimeVal);
				string sendTimeStr = sendTime;
				sendTimeStr[sendTimeStr.length() - 1] = 0;
				cout << recvMsg.substr(0, 4) << " " << inet_ntoa(addrClient.sin_addr) << ": " << ntohs(addrClient.sin_port) << " ------- " << sendTimeStr << " >>>>> " << curTime() << recvMsg.substr(14) << endl;
			}
		}
		//receive异常
		else {
			//Client断线
			if (WSAGetLastError() == 10054) {//Client关闭连接（非Server关闭
				cout << "[System] Lost connection with client " << inet_ntoa(addrClient.sin_addr) << ": " << ntohs(addrClient.sin_port) << endl;
				closesocket(*clientSocket);
				connectionNum--;
				removeClient(addrClient);
				return 0;
			}
			//其他接收失败
			else {
				if (WSAGetLastError() == 10038) {	//断联
					break;
				}
				cout << "[System] Unsuccessful Receiving with exit code " << WSAGetLastError() << endl;
				break;
			}
		}
		Sleep(100);//充分等待分发
		sentNum = 0;
		memset(recvBuf, 0, 1024);
	}
	if (*clientSocket != INVALID_SOCKET)
	{
		closesocket(*clientSocket);
	}
	return 0;
}
//发消息
DWORD WINAPI sender(LPVOID lpParameter) {
	bool needSend = true;
	SOCKET* clientSocket = (SOCKET*)(LPVOID)lpParameter;
	SOCKADDR_IN addrClient;
	int len = sizeof(addrClient);
	getpeername(*clientSocket, (struct sockaddr*)&addrClient, &len);
	//###发消息
	while (true) {
		if (!needSend && recvBuf[0] == 0) {
			needSend = true;
		}
		if (needSend && recvBuf[0] != 0) {
			string recvBufStr = recvBuf;
			if (!strcmp(recvBufStr.substr(14).c_str(), "/exit")) {
				needSend = false;
				continue;
			}
			if (send(*clientSocket, recvBuf, sizeof(recvBuf), 0) < 0) {
				if (WSAGetLastError() == 10054) {//Client关闭连接（非Server关闭）
					cout << "[System] Lost connection with client " << inet_ntoa(addrClient.sin_addr) << ": " << ntohs(addrClient.sin_port) << endl;
					closesocket(*clientSocket);
					connectionNum--;
					removeClient(addrClient);
					return 0;
				}
				else {
					if (WSAGetLastError() == 10038) {	//断联
						break;
					}
					cout << "[System] Unsuccessful Sending with exit code " << WSAGetLastError() << endl;
				}
			}
			else {
				sentNum++;
			}
			needSend = false;
		}
	}
	if (*clientSocket != INVALID_SOCKET)
	{
		closesocket(*clientSocket);
	}
	return 0;
}

int main()
{
	//###初始化
	WSAData wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
		cout << "[System] WSAStartup failed\n";
	}
	//###服务器Socket
	SOCKET socketServer = socket(AF_INET, SOCK_STREAM, 0);
	//###设置地址信息
	SOCKADDR_IN addrServer;
	addrServer.sin_family = AF_INET;//ipv4
	addrServer.sin_addr.S_un.S_addr = (1 << 24) | (0 << 16) | (0 << 8) | 127;//ip
	addrServer.sin_port = htons(port);//端口信息
	//###绑定端口
	if (bind(socketServer, (LPSOCKADDR)&addrServer, sizeof(addrServer))) {
		cout << "[System] Bind failed\n";
		return -1;
	}
	else {
		cout << "[System] Bind server socket to " << inet_ntoa(addrServer.sin_addr) << ": " << ntohs(addrServer.sin_port) << endl;
	}
	//###Server监听
	if (listen(socketServer, MAX_CLIENT_NUM)) {
		cout << "[System] Listen failed\n";
		return -1;
	}
	else {
		cout << "[System] Server established, listening...\n";
	}
	//##接受连接请求
	while (true) {
		//接受Client连接请求，创建Server Thread
		if (connectionNum < MAX_CLIENT_NUM) {
			SOCKET* socketConn = new SOCKET;
			SOCKADDR_IN addrClient;
			int len = sizeof(SOCKADDR);
			*socketConn = accept(socketServer, (SOCKADDR*)&addrClient, &len);
			cout << "[System] Accepted connection from client " << inet_ntoa(addrClient.sin_addr) << ": " << ntohs(addrClient.sin_port) << endl;
			connectionNum++;
			addClient(addrClient);
			char name[5];
			strcpy(name, getname(getid(addrClient)).c_str());
			if (send(*socketConn, name, sizeof(name), 0) < 0) {
				cout << "Unsuccessfully sent name.\n";
			}
			HANDLE hThread1 = CreateThread(NULL, NULL, &sender, (LPVOID)socketConn, 0, NULL);
			HANDLE hThread2 = CreateThread(NULL, NULL, &receiver, (LPVOID)socketConn, 0, NULL);
			CloseHandle(hThread1);
			CloseHandle(hThread2);
		}
	}
	//###关闭Server
	closesocket(socketServer);
	WSACleanup();
	return 0;
}